package cn.mujiankeji.mbrowser.功能.浏览框.webview

import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Resources
import android.graphics.Canvas
import android.graphics.Color
import android.os.Handler
import android.os.Message
import android.view.ActionMode
import android.view.MotionEvent
import android.view.View
import android.view.View.OnTouchListener
import android.webkit.CookieManager
import android.webkit.WebSettings
import android.webkit.WebView
import androidx.webkit.WebSettingsCompat
import cn.mujiankeji.mbrowser.功能.浏览框.助手.浏览框交互助手
import cn.mujiankeji.mbrowser.功能.浏览框.助手.浏览框油猴脚本兼容交互助手
import cn.mujiankeji.mbrowser.数据.配置项.应用配置

import cn.mujiankeji.mbrowser.功能.浏览框.浏览框加载状态
import cn.mujiankeji.mbrowser.功能.浏览框.浏览框状态
import cn.mujiankeji.mbrowser.工具.mlog
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import androidx.core.graphics.withSave
import cn.mujiankeji.mbrowser.功能.浏览框.模型.浏览框功能枚举


@SuppressLint("RequiresFeature", "ClickableViewAccessibility")
class MWebView(
    context : Context,
    val state : 浏览框状态
) : WebView(context) {

    init {
        mlog("MWebView初始化: ${state.uuid.takeLast(6)}")

        setBackgroundColor(Color.WHITE) // 改为白色背景，避免灰色背景引起的视觉白屏
        setInitialScale(0) // 设置初始缩放比例
        
        if (state.页面配置.启用暗色模式){
            try {
                WebSettingsCompat.setForceDarkStrategy(settings, WebSettingsCompat.DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING)
                WebSettingsCompat.setForceDark(settings,WebSettingsCompat.FORCE_DARK_ON)
                //WebSettingsCompat.setAlgorithmicDarkeningAllowed(settings,true)
            }catch (e : Exception){
                e.printStackTrace()
            }
        }

        // 滚动兼容
        overScrollMode = View.OVER_SCROLL_NEVER


        // 设置滚动优化
        isVerticalScrollBarEnabled = false
        isHorizontalScrollBarEnabled = false
        
        // 设置clipToOutline为true，解决Compose中WebView加载完不显示的问题
        clipToOutline = true
        
        // 防止白屏：禁用硬件位图加速
        //setLayerType(View.LAYER_TYPE_HARDWARE, null)
        // settings.setRenderPriority(WebSettings.RenderPriority.HIGH)
        
        // 阻断滚动事件冒泡到Compose
        setOnScrollChangeListener { _, scrollX, scrollY, oldScrollX, oldScrollY -> 
            // 记录滚动事件但不传递给Compose
            if ((scrollX != oldScrollX || scrollY != oldScrollY) && (Math.abs(scrollY - oldScrollY) > 5 || Math.abs(scrollX - oldScrollX) > 5)) {
                // 强制拦截触摸事件，防止滚动事件传递到Compose
                parent?.requestDisallowInterceptTouchEvent(true)
            }
            // 空实现，阻止滚动事件通知Compose系统
        }
        
        // 阻断触摸事件冒泡
        setOnTouchListener { _, event ->
            // 消费所有触摸事件，防止触发Compose重组
            /*when (event.action) {
                MotionEvent.ACTION_DOWN -> {
                    mlog("WebView触摸-按下: x=${event.x}, y=${event.y}")
                    // 按下时立即请求父视图不要拦截触摸事件
                    parent?.requestDisallowInterceptTouchEvent(true)
                }
                MotionEvent.ACTION_MOVE -> {
                    // 拦截滚动手势，阻止Compose重组
                    parent?.requestDisallowInterceptTouchEvent(true)
                    
                    // 只记录有显著移动的手势，减少日志量
                    val dx = Math.abs(event.x - nDownX)
                    val dy = Math.abs(event.y - nDownY)
                    if (dx > 5 || dy > 5) {
                        mlog("WebView触摸-移动: x=${event.x}, y=${event.y}")
                    }
                }
                MotionEvent.ACTION_UP -> {
                    mlog("WebView触摸-抬起: x=${event.x}, y=${event.y}")
                }
                MotionEvent.ACTION_CANCEL -> {
                    mlog("WebView触摸-取消")
                }
            }*/
            // 返回false继续传递给WebView处理
            false
        }

        // 自定义WebViewClient，处理页面加载完成后的刷新
        webViewClient = object : MWebClient(state) {
            override fun onPageFinished(view: WebView?, url: String?) {
                super.onPageFinished(view, url)
                
                // 页面加载完成后强制重绘
                postDelayed({
                    invalidate()
                    // 尝试触发微小滚动以刷新视图
                    scrollBy(0, 1)
                    scrollBy(0, -1)
                }, 100)
            }
        }
        
        webChromeClient = MVueChromeClient(state)

        // 交互
        val 交互助手 = object : 浏览框交互助手(state){}
        addJavascriptInterface(交互助手, "mbrowser")
        addJavascriptInterface(交互助手, "mx_browser_obj")
        addJavascriptInterface(交互助手, "webmx")
        addJavascriptInterface(交互助手, "via")

        // 油猴脚本兼容交互 名称以uuid 动态实现
        addJavascriptInterface(浏览框油猴脚本兼容交互助手(state), "a${state.uuid}")

        // 手势
        初始化手势兼容(this)

        // 长按处理
        setOnLongClickListener(getLongClickListener())

        // 下载
        setDownloadListener {url: String, userAgent: String?, contentDisposition: String?, mimetype: String?, contentLength: Long ->
            // 异常网站不给下载内容
            if (state.网页异常.value) return@setDownloadListener
            state.响应下载?.invoke(url, userAgent ?: settings.userAgentString,
                contentDisposition,
                mimetype,
                contentLength)


            // 空白页则回退
            state.读源码 {
                if (it.length < 30){
                    state.响应销毁页面()
                }
            }
        }
        
        加载配置()
        
        // 添加一些额外的WebView优化，帮助解决白屏问题
        settings.javaScriptEnabled = true
        settings.domStorageEnabled = true
        settings.databaseEnabled = true
        settings.loadsImagesAutomatically = true
        settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
    }

    fun 加载配置(){
        // 默认加载模式
        if (!state.页面配置.极简模式){
            // 启用PC模式则统一谷歌win10
            if (state.页面配置.启用电脑模式) settings.userAgentString = 应用配置.电脑模式标识()
            else if (state.页面配置.UA标识.isNotEmpty()) settings.userAgentString = state.页面配置.UA标识

            //ettings.javaScriptCanOpenWindowsAutomatically = true

            // 缓存
            val 优先读取本地缓存 = false
            if (优先读取本地缓存) {
                settings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK
            } else {
                if (state.页面配置.启用无痕模式) settings.cacheMode = WebSettings.LOAD_NO_CACHE else settings.cacheMode = WebSettings.LOAD_DEFAULT
            }

            // cookie
            val cookieManager = CookieManager.getInstance()
            cookieManager.setAcceptCookie(true)
            cookieManager.setAcceptCookie(true)
            cookieManager.setAcceptThirdPartyCookies(this,state.页面配置.允许第三方Cookie)

            // 无图
            settings.blockNetworkImage = state.页面配置.启用无图模式

            // javascript
            settings.javaScriptEnabled = state.页面配置.启用脚本支持

        }

        settings.useWideViewPort = true
        settings.loadWithOverviewMode = true
        settings.domStorageEnabled = true
        settings.defaultTextEncodingName = "UTF-8"
        settings.allowContentAccess = true
        settings.allowFileAccess = true


        settings.setSupportMultipleWindows(true)
        settings.javaScriptCanOpenWindowsAutomatically = true
        settings.setMediaPlaybackRequiresUserGesture(true);


        /* 自适应屏幕 */
        settings.useWideViewPort = true // 将图片调整到适合webview的大小
        settings.loadWithOverviewMode = true // 缩放至屏幕的大小
        settings.setSupportZoom(true) // 支持缩放
        settings.builtInZoomControls = true // 设置内置的缩放控件。若为false，则该WebView不可缩放
        settings.displayZoomControls = false // 原生的缩放按钮

        /* or */
        settings.allowFileAccess = true
        settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN //自适应屏幕

        //settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); // 页面布局显示样式
        isHorizontalScrollBarEnabled = false
        settings.setGeolocationEnabled(true) // 位置定位
        settings.setNeedInitialFocus(true) // requestFocus(int, android.graphics.Rect)时是否需要设置节点获取焦点，默认值为true。

        // 允许 Https 和 http 加载混合网络协议
        settings.allowFileAccessFromFileURLs = true
        settings.allowUniversalAccessFromFileURLs = true
        settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW

        // 字体
        // settings.standardFontFamily = "sans-serif" //设置 WebView 的字体，默认字体为 "sans-serif"

        settings.defaultFixedFontSize = 16
        settings.defaultFontSize = 16 //设置 WebView 字体的大小，默认大小为 16
        settings.minimumFontSize = 10 //设置 WebView 支持的最小字体大小，默认为 8

        settings.textZoom = runBlocking { 应用配置.读取浏览框字体缩放比例().first() }
        settings.defaultTextEncodingName = "UTF-8" //设置编码格式


        // 缓存
        //webview 中localStorage无效的解决方法
        settings.databaseEnabled = true
        settings.domStorageEnabled = true //DOM存储API是否可用,默认false
        settings.savePassword = true

        //String appCachePath = getContext().getCacheDir().getAbsolutePath();
        val appCachePath = context.cacheDir.absolutePath + "/webcache"
        settings.setGeolocationDatabasePath(appCachePath)
        //settings.setAppCachePath(appCachePath)
        settings.allowFileAccess = true //是否允许访问文件,默认允许

        //settings.setAppCacheEnabled(true) //应用缓存API是否可用,默认值false,结合setAppCachePath(String)使用

        // 优化渲染速度
        settings.setRenderPriority(WebSettings.RenderPriority.HIGH)
        
        // 关闭滚动条淡出效果
        isScrollbarFadingEnabled = false
    }

    override fun onDraw(canvas: Canvas) {
        // 使用双重缓冲绘制，减少闪烁
        try {
            canvas.withSave {
                super.onDraw(canvas)
            }
        } catch (e: Exception) {
            // 捕获渲染异常
            e.printStackTrace()
            // 尝试恢复渲染
            postInvalidate()
        }
    }
    /**
     * 覆盖方法，使WebView的测量和布局更高效
     */
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }

    override fun reload() {
        加载配置()
        super.reload()
    }
    private fun onStartLoad(url : String){
        state.重置()
        state.地址.value = url
        try {
            加载配置()
            clearCache(true)
            clearHistory()
        }catch (e : Exception){
            e.printStackTrace()
        }
    }
    override fun loadUrl(url: String) {
        loadUrl(url,"",null)
    }
    fun loadUrl(url: String,referer : String,post : String?) {
        if (!url.startsWith("javascript")){
            onStartLoad(url)
            if (referer.isNotEmpty()){
                val heads : MutableMap<String,String> = HashMap()
                heads.put("Referer",referer.trim())
                super.loadUrl(url,heads)
            }
            else{
                if (!post.isNullOrEmpty()){
                    super.postUrl(url,post.toByteArray())
                }
                else{
                    super.loadUrl(url)
                }
            }
        }

        else{
            super.loadUrl(url)
        }
    }

    override fun loadData(data: String, mimeType: String?, encoding: String?) {
        onStartLoad("")
        super.loadData(data, mimeType, encoding)
    }
    override fun loadDataWithBaseURL(baseUrl: String?, data: String, mimeType: String?, encoding: String?, historyUrl: String?) {
        onStartLoad(baseUrl?:"")
        super.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl)
    }

    // -- 脚本及交互 --
    fun 注入脚本(script : String){
        if (!state.是否暂停.value) evaluateJavascript(script) {}
    }

    // -- 手势处理 --
    var nDownX : Float = 0f
    var nDownY : Float = 0f
    var 是否为用户手势: Boolean = false // 用户手势操作中
    @SuppressLint("ClickableViewAccessibility")
    fun 初始化手势兼容(view : View) {
        fun px2dip(px: Int): Int {
            val scale = Resources.getSystem().displayMetrics.density
            return (px / scale + 0.5f).toInt()
        }

        view.setOnTouchListener(OnTouchListener { v: View?, event: MotionEvent ->
            if (event.action == MotionEvent.ACTION_DOWN) {
                if (state.状态== 浏览框加载状态.静态元素加载完毕){
                    view.parent.requestDisallowInterceptTouchEvent(true)
                }
                else {
                    view.parent.requestDisallowInterceptTouchEvent(false)
                }
                nDownX = event.rawX
                nDownY = event.rawY
            }
            else if (event.action == MotionEvent.ACTION_UP) {
                // 模拟点击指定局域，防止手动点击webview导致的跳动
                if (state.启用开发者模式 && !是否为用户手势) {
                    val x = px2dip(nDownX.toInt())
                    val y = px2dip(nDownY.toInt())
                    // 元素真实位置
                    注入脚本("t_change_element(document.elementFromPoint($x,$y))")
                    return@OnTouchListener true
                }
            }
            else if (event.action == MotionEvent.ACTION_MOVE) {
                if (是否为用户手势) return@OnTouchListener false // 就不用重复计算了
                val dx = Math.abs(event.x - nDownX)
                val dy = Math.abs(event.y - nDownY)
                是否为用户手势 = dx > 10 || dy > 10
                
                if (是否为用户手势) {
                    mlog("WebView手势-检测到用户滚动: dx=$dx, dy=$dy")
                    // 确保父视图不拦截滚动事件
                    view.parent.requestDisallowInterceptTouchEvent(true)
                }
            }
            false
        })
    }


    // -- 长按处理 --
    var 长按选中地址: String? = null // a.href
    var 长按选中图片地址: String? = null // img.src
    var 长按选中标题: String? = null // 正文
    public fun getLongClickListener(): OnLongClickListener {
        return OnLongClickListener { v: View? ->
            // 调试状态不响应长按
            if (state.启用开发者模式) return@OnLongClickListener true

            // 获取点击位置内容
            val msg = Message()
            msg.target = Handler{ mes: Message? ->
                长按选中地址 = msg.data.getString("url")
                长按选中图片地址 = msg.data.getString("src")
                长按选中标题 = msg.data.getString("title")
                false
            }
            requestFocusNodeHref(msg)

            when(hitTestResult.type){
                HitTestResult.UNKNOWN_TYPE, HitTestResult.GEO_TYPE -> return@OnLongClickListener false

                // a地址
                HitTestResult.SRC_ANCHOR_TYPE -> {
                    state.响应显示菜单?.invoke(listOf(浏览框功能枚举.打开地址,浏览框功能枚举.新窗口打开,
                        浏览框功能枚举.复制地址))
                }
                // 图片
                HitTestResult.IMAGE_TYPE -> {
                    state.响应显示菜单?.invoke(listOf(浏览框功能枚举.查看图片,浏览框功能枚举.保存图片,
                        浏览框功能枚举.识别二维码,
                        浏览框功能枚举.标记广告))
                }

                // 带a链接 的图片
                HitTestResult.SRC_IMAGE_ANCHOR_TYPE -> {
                    state.响应显示菜单?.invoke(listOf(浏览框功能枚举.打开地址,浏览框功能枚举.新窗口打开,
                        浏览框功能枚举.复制地址,
                        浏览框功能枚举.查看图片,浏览框功能枚举.保存图片,
                        浏览框功能枚举.识别二维码,
                        浏览框功能枚举.标记广告))
                }

                else -> return@OnLongClickListener false

            }
            return@OnLongClickListener true
        }
    }

    /**
     * 创建菜单 这个比较复杂，看旧版是需要在 activity中替换的 先不处理
     */
    var nSelectTextAction: ActionMode? = null
    override fun startActionMode(callback: ActionMode.Callback, type: Int): ActionMode? {
        mlog("start ActionMode",callback)
        return super.startActionMode(callback, type)
    }

    /**
     * 覆盖dispatchTouchEvent方法，更早地拦截触摸事件
     */
    override fun dispatchTouchEvent(event: MotionEvent): Boolean {
        // 记录初始触摸位置，用于手势检测
        if (event.action == MotionEvent.ACTION_DOWN) {
            nDownX = event.x
            nDownY = event.y
        }
        
        // 在WebView内容加载完成后，完全处理触摸事件，不让事件冒泡到Compose
        if (state.状态 == 浏览框加载状态.静态元素加载完毕) {
            parent?.requestDisallowInterceptTouchEvent(true)
        }
        
        return super.dispatchTouchEvent(event)
    }
    
    /**
     * 覆盖onTouchEvent，确保WebView完全处理触摸事件
     */
    override fun onTouchEvent(event: MotionEvent): Boolean {
        // 在滚动过程中，防止事件冒泡
        if (event.action == MotionEvent.ACTION_MOVE) {
            parent?.requestDisallowInterceptTouchEvent(true)
        }
        
        return super.onTouchEvent(event)
    }


    /**
     * 强制触发WebView渲染
     * 解决从后台切换回来才显示的问题
     */
    fun 强制触发渲染() {
        // 触发硬件加速层重绘，但不使用过于激进的方法
        invalidate()
        requestLayout()
        
        // 使用更平滑的透明度变化，减少闪烁
        if (alpha == 1.0f) {
            animate()
                .alpha(0.99f)
                .setDuration(1)
                .withEndAction {
                    animate()
                        .alpha(1.0f)
                        .setDuration(1)
                        .start()
                }
                .start()
        }
        
        // 触发合成器刷新
        setWillNotDraw(false)
        postInvalidateOnAnimation()
        
        // 只在必要时切换渲染模式
        if (state.状态 != 浏览框加载状态.静态元素加载完毕 && state.状态 != 浏览框加载状态.加载完毕) {
            切换渲染模式解决白屏()
        }
    }
    
    /**
     * 临时切换渲染模式解决白屏问题
     */
    fun 切换渲染模式解决白屏() {
        // 临时切换到软件渲染再切回硬件渲染，但减少视觉闪烁
        val currentType = layerType
        // 只有当前不是软件渲染时才切换
        if (currentType != View.LAYER_TYPE_SOFTWARE) {
            setLayerType(View.LAYER_TYPE_SOFTWARE, null)
            postDelayed({
                setLayerType(currentType, null)
                // 使用更温和的方式触发重绘
                postInvalidateOnAnimation()
            }, 30)
        }
    }


    
    /**
     * 监听窗口可见性变化
     */
    override fun onWindowVisibilityChanged(visibility: Int) {
        super.onWindowVisibilityChanged(visibility)
        if (visibility == View.VISIBLE) {
            // 视图变为可见时强制渲染
            postDelayed({ 强制触发渲染() }, 100)
        }
    }
}

